package com.finger.gulimall.search.thread;

import java.util.concurrent.*;

/**
 * 回顾线程
 */
public class ThreadTest {

    public static ExecutorService executor = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main start。。");
        // 第一种异步编排的启动方式,无返回值
        /*CompletableFuture.runAsync(()->{
            System.out.println("当前线程为：" + Thread.currentThread().getId());
            int i = 10 / 5;
            System.out.println("返回结果：" + i);
        },executor);
         */
        // 第二种异步编排的启动方式,阻塞式等待，可以获取返回结果
        /*
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程为：" + Thread.currentThread().getId());
            int i = 10 / 5;
            System.out.println("返回结果：" + i);
            return i;
        }, executor);
        Integer integer = future.get();
        System.out.println(integer);
         */
        // 串行化执行
        /*
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程为：" + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("返回结果：" + i);
            return i;
        }, executor).whenComplete((res,exception)->{ // whenComplete：当上一个异步方法执行完之后执行该方法，res：上一个方法的返回结果,exception：上一个方法出现异常会传入该异常
            System.out.println("后续方法调用。。结果是："+res+"异常是："+exception);
        }).exceptionally(exception ->{ // 出现异常后执行该方法，exception：出现的异常

            return 1;
        });
         */
        // handle：当所有方法执行完之后执行该方法，如果中间出现异常则结果值会传入null
       /*
        CompletableFuture<Integer> handle = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程为：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("返回结果：" + i);
            return i;
        }, executor).handle((res, exception) -> { // handle：当所有方法执行完之后执行该方法，如果中间出现异常则结果值会传入null
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return res * 2;
        });
        Integer integer = handle.get();
        */

        /**
         * 两个任务必须都完成，触发该任务
         *      thenCombine：组合两个future，获取两个future的返回结果，并返回当前任务的返回值
         *      thenAcceptBoth：组合两个future，获取两个future任务的返回结果，然后处理任务，没有返回值
         *      runAfterBoth：组合两个future，不需要获取future的结果，只需要两个future处理完任务后，处理该任务
         */

        /**
         * 当两个任务中，任意一个future任务完成的时候，执行任务。
         *      applyToEither：两个任务有一个完成执行，获取它的返回值，处理任务并有新的返回值
         *      acceptEither：两个任务有一个执行完成，获取它的返回值，处理任务，没有新的返回值。
         *      runAfterEither：两个任务有一个执行完成，不需要获取future的结果，处理任务，也没有返回值
         */
        System.out.println("main start。。");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程为：" + Thread.currentThread().getId());
            int i = 10 / 5;
            System.out.println("返回结果：" + i);
            return i;
        }, executor);
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程为 future1：" + Thread.currentThread().getId());

            return "Hello";
        });
        // future.thenAcceptBothAsync 当两个执行完之后执行
        CompletableFuture<String> future2 = future.thenCombineAsync(future1, (i, j) -> {
            return i + j;
        }, executor);

        System.out.println("main end。。" + future2.get());
    }

    public static void testCreateThread(String[] args) throws ExecutionException, InterruptedException {
        /**
         * 创建多线程有四种方法：
         *   第一种：继承Thread类
         *      System.out.println("mian start。。");
         *      new Thread01().start();
         *      System.out.println("main end。。");
         *
         *   第二种：实现Runnable接口
         *      System.out.println("mian start。。");
         *      new Thread(new Thread02()).start();
         *      System.out.println("main end。。");
         *
         *   第三种：实现 Callable<T>接口，泛型可以指定返回结果,阻塞式等待，可以拿到返回结果
         *      FutureTask<Integer> futureTask = new FutureTask(new Thread03());
         *      new Thread(futureTask).start();
         *      Integer o = futureTask.get();
         *
         *   第四种：线程池
         *      ExecutorService executorService = Executors.newFixedThreadPool(10);
         *      executorService.submit(new Thread02());
         *    区别：
         *      1、2种方法不能获取返回值，
         *      1、2、3种方法不能控制资源
         *      4 可以控制资源，性能稳定
         *      所以一般都用线程池方法
         *    线程池创建：
         *           Executors.newFixedThreadPool()
         *           new ThreadPoolExecutor()
         *
         *   ThreadPoolExecutor的七大参数
         *   int corePoolSize：指定线程存活的核心数量，无论有没有任务这些线程都会存活
         *   int maximumPoolSize：指定线程的最大数量，核心线程满了之后就算任务再多也不会超过这个指定的数值
         *   long keepAliveTime：最大存活时间，指当前线程数已经超过了核心(core)线程数，处理完任务之后空闲下来这些多出来的线程将会存活指定的时间，之后回收
         *   TimeUnit unit：指存活（keepAliveTime）的时间单位
         *   BlockingQueue<Runnable> workQueue：线程队列，当核心线程数达到之后，会将任务存放到线程队列中，核心线程空闲下来之后会按先后顺序处理。可以指定这个线程队列的大小，默认大小是Integer的最大值
         *   ThreadFactory threadFactory：线程工厂
         *   RejectedExecutionHandler handler：指定拒绝策略，指核心线程满了，线程队列满了，并且线程数也达到了指定线程数的最大数量，之后过来的任务就会被指定的拒绝策列拒绝
         *
         *     7个核心线程，50个线程队列， 最大线程20个 ， 100个请求怎么分配：
         *          7个任务立即执行，然后50个请求进入线程队列，再开辟13个线程执行任务，剩下30个请求使用拒绝策略拒绝
         */

        System.out.println("mian start。。");

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,
                200,
                100,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue(10000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy());
        System.out.println("main end。。");
    }

    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("当前线程为：" + Thread.currentThread().getId());
            int i = 10 / 5;
            System.out.println("返回结果：" + i);
        }
    }

    public static class Thread02 implements Runnable {
        @Override
        public void run() {
            System.out.println("当前线程为：" + Thread.currentThread().getId());
            int i = 10 / 5;
            System.out.println("返回结果：" + i);
        }
    }

    public static class Thread03 implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程为：" + Thread.currentThread().getId());
            int i = 10 / 5;
            System.out.println("返回结果：" + i);
            return i;
        }
    }


}
